class Snake
{
	//public:
	private:
		coordList *snakeBody;
		char snakeDirection;

	public:
		coordList *firstPrevState;
		coordList *lastPrevState;

		Snake(void)
		{
			snakeBody = new coordList;

			snakeBody->x = 1;
			snakeBody->y = 2;
			snakeBody->z = 5;
			snakeBody->nextPtr = new coordList;

			snakeBody->nextPtr->x = 2;
			snakeBody->nextPtr->y = 2;
			snakeBody->nextPtr->z = 5;

			snakeBody->nextPtr->nextPtr = new coordList;

			snakeBody->nextPtr->nextPtr->x = 3;
			snakeBody->nextPtr->nextPtr->y = 2;
			snakeBody->nextPtr->nextPtr->z = 5;

			snakeBody->nextPtr->nextPtr->nextPtr = 0;
		}
		~Snake(void)
		{
			delete snakeBody->nextPtr->nextPtr;
			delete snakeBody->nextPtr;
			delete snakeBody;
		}

		void changeDirection( char direction );
		void moveSnake( coordList *apple );
		(coordList *) createFutureSnakeHead( void );
		int collisionWithApple( coordList *futureSnakeHead, coordList *apple );
		void addBodyPart( coordList *futureSnakeHead );		
		int collisionWithSelf( coordList *futureHead, coordList *snake);
		int collisionWithWalls( coordList *futureSnakeHead);

		void displayListNodes( coordList* ptr );	

		void cycleListNodes( coordList*& listPtr, int& count, coordList*& second2LastLink, coordList**& finalLink );
		(coordList *) giveSnake();
};

void Snake::changeDirection( char direction )
{
	snakeDirection = direction;
}

void Snake::moveSnake( coordList *apple )
{	
	coordList *futureSnakeHead = createFutureSnakeHead();
	
	if( collisionWithApple( futureSnakeHead, apple) )
	{
		addBodyPart( futureSnakeHead );
		appleObj.respawn( snakeBody );		
	}
	else if( collisionWithSelf( futureSnakeHead, snakeBody ) || collisionWithWalls( futureSnakeHead ) )
	{
		// Game Over
		cout << "Game Over." << endl;
	}
	else
	{	
		// Moving and no collision

		coordList *tempPtr = snakeBody;
		int tempInt = 0;
		int& count = tempInt;
		
		coordList* pointToLastNode;
		coordList** lastNodeNextPtr;
		//cout << "            Begin: list, elements, list" << endl;
		//displayListNodes( snakeBody );
		//cout << endl;
		cycleListNodes( snakeBody, count, pointToLastNode, lastNodeNextPtr );
		
		if( count > 1 )
		{
			//secondPtr = snakeBody;

			tempPtr = snakeBody;
			snakeBody = pointToLastNode;
			//snakeBody->x = tempPtr->x;
			*lastNodeNextPtr = tempPtr;
		}
		
		snakeBody->x = futureSnakeHead->x;
		snakeBody->y = futureSnakeHead->y;
		snakeBody->z = futureSnakeHead->z;
	}

	delete futureSnakeHead;
}

coordList * Snake::createFutureSnakeHead()
{
	coordList *future = new coordList;
	
	switch( snakeDirection )
	{
		case 'U':
			future->x = snakeBody->x;
			future->y = snakeBody->y + 1;
			future->z = snakeBody->z;
			break;
		case 'D':
			future->x = snakeBody->x;
			future->y = snakeBody->y - 1;
			future->z = snakeBody->z;
			break;
		case 'R':
			future->x = snakeBody->x + 1;
			future->y = snakeBody->y;
			future->z = snakeBody->z;
			break;
		case 'L':
			future->x = snakeBody->x - 1;
			future->y = snakeBody->y;
			future->z = snakeBody->z;
			break;
		case 'F':
			future->x = snakeBody->x;
			future->y = snakeBody->y;
			future->z = snakeBody->z + 1;
			break;
		case 'B':
		default:
			future->x = snakeBody->x;
			future->y = snakeBody->y;
			future->z = snakeBody->z - 1;
			break;
	}

	return future;
}

int Snake::collisionWithApple( coordList* futureSnakeHead, coordList* apple )
{
	if( apple->x == futureSnakeHead->x && apple->y == futureSnakeHead->y && apple->z == futureSnakeHead->z )
	{
		return 1;
	}

	return 0;
}

void Snake::addBodyPart( coordList* futureSnakeHead )
{
	coordList *temp = snakeBody;
	snakeBody = new coordList;
	snakeBody->x = futureSnakeHead->x;
	snakeBody->y = futureSnakeHead->y;
	snakeBody->z = futureSnakeHead->z;
	snakeBody->nextPtr = temp;
}

int Snake::collisionWithSelf( coordList *futureHead, coordList *source )
{
	if( futureHead->x == source->x && futureHead->y == source->y && futureHead->z == source->z )
	{
		cout << "Collision With Self" << endl;
		return 1;
	}

	if( source->nextPtr != NULL )
	{
		collisionWithSelf( futureHead, source->nextPtr );
	}
	else
	{
		return 0;
	}
}

int Snake::collisionWithWalls( coordList *source )
{
	if( source->x > 15	|| source->y > 15	|| source->z > 15 ||
		source->x < 0	|| source->y < 0	|| source->z < 0	)
	{
		cout << "Collision With Walls" << endl;
		return 1;
	}

	return 0;
}








void Snake::cycleListNodes( coordList*& source, int& count, coordList*& second2LastLink, coordList**& finalLink )
{
	count++;

	if( count == 1 )
	{
		
	}

	if( source->nextPtr != 0 )
	{
		cycleListNodes( source->nextPtr, count, second2LastLink, finalLink );		
	}
	else
	{
		if( count > 1 )
		{
			finalLink = &source->nextPtr;		
			second2LastLink = source;
			source = NULL;
		}


	}
}

void Snake::displayListNodes( coordList* ptr )
{
	cout << ptr->x << " " << ptr->y << " " << ptr->z << endl;
	if( ptr->nextPtr != 0 )
	{
		displayListNodes( ptr->nextPtr );
	}
}

coordList * Snake::giveSnake()
{
	return snakeBody;
}